<script setup lang="ts">
import Common from "./common.vue";
import { onBeforeRouteLeave, useRoute, useRouter } from "vue-router";
import dayjs from "dayjs";
import { getCorrectCount, getWrongCount } from "./common";
import { showDialog } from "@nutui/nutui";
import _ from "lodash";
import "@nutui/nutui/dist/packages/dialog/style";
import {
  PracticeStatus,
  Question,
  QuestionActionRecord,
  QuestionActionRecordSource,
  QuestionActionRecordWithId,
  QuestionOptionIndex,
  QuestionState,
  Subject,
  UpdateActionRecordParams,
} from "@/types/practice";
import * as QuestionApi from "@/api/train/question";
import * as PaperApi from "@/api/train/paper";
import { Course } from "@/types/course";
import { PaperRecordCreateReq } from "@/api/train/paper";

const route = useRoute();
const router = useRouter();

// 模考专属变量
const carType = +(route.query.carType ?? "1") as Question["carType"];
const subject = +(route.query.subject ?? "1") as Question["subject"];

// 课程id
const courseId = route.query.courseId as Course["id"];

// 单题分数
const unitScore = {
  // 科一：每题1分
  [Subject.ONE]: 1,
  // 科四：每题2分
  [Subject.FOUR]: 2,
}[subject];

// TODO: 通过接口获取当前考卷的批次号
const batchId = Date.now() + "";

const loadQuestionIds = () =>
  QuestionApi.listMemberPaperIds(carType, subject).then((res) => {
    return res.data;
  });

/** 加载题目id列表 */
const questionIds = ref<Question["id"][]>([]);

/** 收藏记录 */
const collectRecordMap = reactive(new Map<Question["id"], boolean>());
/** 更新收藏记录 */
const handleUpdateCollectRecord = (questionId: Question["id"], isCollect: boolean) => collectRecordMap.set(questionId, isCollect);
/** 上传收藏记录 */
const handleUploadCollectRecord = () => {
  const status: QuestionApi.CollectRecordInfo[] = [];
  collectRecordMap.forEach((value, key) => status.push({ questionId: key, ifCollect: value }));
  QuestionApi.createOrUpdateMemberCourseCollect(courseId, status);
};

/** 存储模考本地错题记录 */
const actionRecordMap = reactive(new Map<Question["id"], QuestionActionRecordWithId>());
/** 做题记录模板 */
const actionRecordTemplate: QuestionActionRecord = {
  carType,
  subject,
  lastErrorAnswerRecord: null,
  actionCount: 0,
  errorCount: 0,
  updatedAt: 0,
};
/** 更新做题记录 */
const handleUpdateActionRecord = (params: UpdateActionRecordParams) => {
  const actionRecord = actionRecordMap.get(params.questionId);
  if (actionRecord) {
    actionRecord.actionCount++;
    actionRecord.lastErrorAnswerRecord = params.isCorrect;
    !params.isCorrect && actionRecord.errorCount++;
    actionRecord.updatedAt = Date.now();
  } else {
    actionRecordMap.set(params.questionId, {
      questionId: params.questionId,
      carType: actionRecordTemplate.carType,
      subject: actionRecordTemplate.subject,
      lastErrorAnswerRecord: params.isCorrect,
      actionCount: 1,
      errorCount: params.isCorrect ? 0 : 1,
      updatedAt: Date.now(),
    });
  }
};
/** 上传做题记录 */
const handleUploadActionRecord = () => {
  const actionRecords: QuestionActionRecordWithId[] = Array.from(actionRecordMap.values());
  QuestionApi.batchCreateOrUpdateMemberActionRecord(QuestionActionRecordSource.EXAM, batchId, actionRecords);
};

// 已加载的id和题目的映射
const questionsMap = ref<Map<Question["id"], Question>>(new Map());

/** 整合的题目记录 */
const questionsStateMap = computed(() =>
  questionIds.value.reduce((prev, cur) => {
    const state: QuestionState = {
      loadState: "silent",
      actionRecord: actionRecordMap.get(cur) || actionRecordTemplate,
      question: questionsMap.value.get(cur) || null,
      isCollect: collectRecordMap.get(cur) || false,
    };
    prev.set(cur, state);
    return prev;
  }, new Map<Question["id"], QuestionState>())
);

/** 初始化题目id列表 */
loadQuestionIds().then(async (ids) => {
  // 填充id列表
  questionIds.value = ids;

  // 加载收藏记录
  const collectRecordRes = await QuestionApi.listMemberCollectRecord(courseId);
  collectRecordRes.data.forEach((questionId) => collectRecordMap.set(questionId, true));
});

/** 离开页面时上传记录 */
onBeforeRouteLeave(() => {
  handleUploadActionRecord();
  handleUploadCollectRecord();
});

// 答案记录
const questionChoosedAnswerMap = ref(new Map<Question["id"], QuestionOptionIndex[]>());

// 做题记录统计数据
const correctCount = computed(() => getCorrectCount(actionRecordMap));
const wrongCount = computed(() => getWrongCount(actionRecordMap));

// 是否全部题目都做完了
const allDone = computed(() => questionChoosedAnswerMap.value.size === questionIds.value.length);
// 未答题数
const unAnswerCount = computed(() => questionIds.value.length - questionChoosedAnswerMap.value.size);

// 考试得分
const score = computed(() => correctCount.value * unitScore);
// 失分
const lostScore = computed(() => wrongCount.value * unitScore);

// 考试倒计时
const practiceTotalSecond = 45 * 60;
const practiceTimeSecond = ref(practiceTotalSecond);
const practiceTimeText = computed(() => dayjs(practiceTimeSecond.value * 1000).format("mm:ss"));

// 交卷弹窗是否可见
const submitPopupVisible = ref(false);

/**
 * 倒计时定时器
 */
const practiceTimeInterval = setInterval(() => {
  if (submitPopupVisible.value) return;

  if (practiceTimeSecond.value > 0) practiceTimeSecond.value -= 1;
  else {
    clearInterval(practiceTimeInterval);
    handleTimeEnd();
  }
}, 1000);

// 弹窗展示信息
const popupData = [
  {
    highlight: true,
    value: unAnswerCount,
    text: "未答题数",
  },
  {
    value: wrongCount,
    text: "错题数",
  },
  {
    value: score,
    text: "考试得分",
  },
];

// 交卷
const submitPaper = () => {
  const paperId = Date.now();
  const paperRecord: PaperRecordCreateReq = {
    carType,
    subject,
    paperId,
    duration: practiceTotalSecond - practiceTimeSecond.value,
    completed: allDone.value,
    passed: score.value >= 90,
    score: score.value,
  };

  // 刷新个性化题目题目
  QuestionApi.initPersonalPaper(carType, subject).then((res) => console.log("刷新题目：", res));

  // 创建模考记录
  PaperApi.createPaperRecord(paperRecord).then((res) => {
    if (res.data) router.replace(`/practice/result/${paperId}`);
  });
};

// 考试状态
const practiceStatus = ref<PracticeStatus>("normal");
const practicePopupContent = computed(
  () =>
    ({
      normal: {
        title: "已暂停",
        actions: [
          {
            text: "继续答题",
            highlight: !allDone.value,
            handleClick: () => {
              submitPopupVisible.value = false;
            },
          },
          {
            text: "现在交卷",
            highlight: allDone.value,
            handleClick: () => {
              submitPaper();
            },
          },
        ],
      },
      "time-end": {
        title: "时间到",
        actions: [
          {
            text: "继续答题",
            highlight: !allDone.value,
            handleClick: () => {
              practiceStatus.value = "abandon-overtime";
              submitPopupVisible.value = false;
            },
          },
          {
            text: "现在交卷",
            highlight: allDone.value,
            handleClick: () => {
              submitPaper();
            },
          },
        ],
      },
      "abandon-overtime": {
        title: "已超时",
        actions: [
          {
            text: "继续答题",
            highlight: !allDone.value,
            handleClick: () => {
              submitPopupVisible.value = false;
            },
          },
          {
            text: "查看统计",
            highlight: allDone.value,
            handleClick: () => {
              submitPaper();
            },
          },
        ],
      },
      "abandon-flunk": {
        title: "不及格",
        actions: [
          {
            text: "继续答题",
            highlight: !allDone.value,
            handleClick: () => {
              submitPopupVisible.value = false;
            },
          },
          {
            text: "现在交卷",
            highlight: allDone.value,
            handleClick: () => {
              submitPaper();
            },
          },
        ],
      },
    })[practiceStatus.value]
);

/**
 * 选择答案
 * @param questionId 题目id
 * @param optionIndexList 选项
 * @param isCorrect 是否正确
 */
const handleChooseAnswer = (questionId: Question["id"], optionIndexList: QuestionOptionIndex[], isCorrect: boolean) => {
  questionChoosedAnswerMap.value.set(questionId, optionIndexList);
};

// 失分超过10分就不及格
watch(lostScore, (value) => {
  if (practiceStatus.value !== "abandon-flunk" && value > 10) {
    practiceStatus.value = "abandon-flunk";
    submitPopupVisible.value = true;
  }
});

const commonRef = ref();

/**
 * 做到最后一题
 */
const handleEnd = () => {
  // TODO: 弹窗询问：未完成全部题目，是否提交或跳转到未做题目，提交后不可更改，提交的话就把答案全部填满
  const index = questionIds.value.findIndex((id) => !questionChoosedAnswerMap.value.has(id));
  console.log(index);
  if (index === -1) {
    submitPopupVisible.value = true;
  } else {
    showDialog({
      title: "提示",
      content: "还有题目未填写，是否跳转答题？",
      onOk: () => {
        commonRef.value.goto(index);
      },
      onCancel: handleSubmit,
    });
  }
};

/**
 * 倒计时结束
 */
const handleTimeEnd = () => {
  if (practiceStatus.value.startsWith("abandon")) return;
  practiceStatus.value = "time-end";
  submitPopupVisible.value = true;
};

/**
 * 用户点击提交
 */
const handleSubmit = () => {
  submitPopupVisible.value = true;
};
</script>

<template>
  <div class="min-h-screen bg-gray-1 flex flex-col">
    <!-- 顶部栏倒计时 -->
    <div class="h-12 shrink-0 bg-white shadow flex justify-center items-center">
      <span>倒计时 {{ practiceTimeText }}</span>
    </div>

    <Common
      ref="commonRef"
      practice-mode="exam"
      v-model:questions-map="questionsMap"
      :question-ids="questionIds"
      :questions-state-map="questionsStateMap"
      :question-choosed-answer-map="questionChoosedAnswerMap"
      :correct-count="correctCount"
      :wrong-count="wrongCount"
      show-submit
      @submit="handleSubmit"
      @choose-answer="handleChooseAnswer"
      @update-collect-record="handleUpdateCollectRecord"
      @update-action-record="handleUpdateActionRecord"
      @end="handleEnd"
    />

    <!-- 完成答题后的弹窗 -->
    <nut-popup :visible="submitPopupVisible" round>
      <div class="w-72 flex flex-col items-center py-5 px-7 bg-white">
        <!-- 标题 -->
        <h2 class="text-xl c-red-7">{{ practicePopupContent.title }}</h2>
        <!-- 剩余时间 -->
        <p class="py-3 text-sm c-gray-5">剩余时间 {{ practiceTimeText }}</p>
        <!-- 未答题数、错题数、考试得分 -->
        <div class="w-full flex justify-between">
          <div v-for="item in popupData" :key="item.text" class="flex flex-col items-center">
            <p class="text-2xl" :class="{ 'c-green-5': item.highlight }">{{ item.value }}</p>
            <p class="text-sm c-gray-5">{{ item.text }}</p>
          </div>
        </div>
        <!-- 按钮 -->
        <div class="pt-5 w-full flex justify-between">
          <button
            v-for="item in practicePopupContent.actions"
            :key="item.text"
            class="px-5 py-1 text-sm rd-full"
            :class="{ 'bg-green-5 c-white': item.highlight, 'b-2 b-solid b-gray-2': !item.highlight }"
            @click="item.handleClick"
          >
            {{ item.text }}
          </button>
        </div>
      </div>
    </nut-popup>
  </div>
</template>
